#pragma once
#include <iostream>
#include <unordered_map>
#include <fstream>
#include <string>
#include <filesystem>
#include <vector>
#include <sstream>
#include <sys/socket.h>
#include "Socket.hpp"

static const int defaultport = 8080;

const std::string webroot = "./webroot";
const std::string sep = "\r\n";
const std::string homepath = "index.html";

class HttpServer;

class ThreadData
{
public:
    ThreadData(int fd, HttpServer* svr) : sockfd(fd), httpsvr(svr)
    {}
public:
    int sockfd;
    HttpServer* httpsvr;
};

class HttpRequest
{
public:
    HttpRequest(/* args */) = default;
    ~HttpRequest() = default;

    void Parse()
    {
        std::stringstream ss(req_header[0]);
        ss >> method >> url >> http_servion;

        file_path = webroot;
        if(url == "/" || url == "/index.html")  
        {
            file_path += '/';
            file_path += homepath;
        }
        else file_path += url;  

        auto pos =  file_path.rfind('.');
        if(pos == std::string::npos) suffix = ".html";
        else suffix = file_path.substr(pos);
    }

    void Deserialize(std::string req)
    {
        while (true)
        {
            size_t pos = req.find(sep);
            if(pos == std::string::npos) break;
            std::string tmp = req.substr(0, pos);
            if(tmp.empty()) break;
            req_header.emplace_back(tmp);
            req.erase(0, pos + sep.size());
        }        
        text = req;
    }

    void DebugPrint()
    {
        for(auto& line : req_header) 
        {
            std::cout << "-------------------------------\n";
            std::cout << line << "\n";
        }
        cout << "method: " << method << "\n";
        cout << "url: " << url << "\n";
        cout << "http_servion: " << http_servion << "\n";
        cout << "file_path: " << file_path << "\n";
        std::cout << text << "\n";
    }
public:
    std::vector<std::string> req_header;    // 请求行
    std::string text;       // 正文

    std::string method;     // 解析后的参数
    std::string url;
    std::string http_servion;
    std::string file_path;

    std::string suffix;     // 资源后缀
};

class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport) : port_(port)
    {
        contentType_.emplace(".html", "text/html");
        contentType_.emplace(".png", "image/png");
        contentType_.emplace(".jpeg", "image/jpeg");
    }
    ~HttpServer() = default;

    bool start()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        lg(Info, "server init ... done");
        for(;;)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            lg(Info, "get a new connect, sockfd: %d", sockfd);
            pthread_t tid;
            ThreadData* td = new ThreadData(sockfd, this);
            pthread_create(&tid, nullptr, ThreadFunc, td);
        }
    }

    std::string SuffixToDesc(const std::string& suffix)
    {
        auto iter = contentType_.find(suffix);
        if(iter == contentType_.end()) return contentType_[".html"];
        else return contentType_[suffix];
    }

    static std::string ReadHtmlContent(const std::string& path)
    {
        std::ifstream in(path, std::ios::binary);    // 二进制读
        if(!in.is_open())
        {
            std::cerr << "Error opening file: " << path << std::endl;
            return "";
        }
        
        // std::string content, line;
        // while (std::getline(in, line))
        // {
        //     content += line;
        // }

        in.seekg(0, std::ios_base::end);    // 文件指针定位到文件尾
        auto len = in.tellg();              // 获取文件大小
        in.seekg(0, std::ios_base::beg);    // 定位到开头

        std::string content;
        content.resize(len);
        in.read((char*)content.c_str(), content.size());

        in.close();
        return content;
    }

    void HandlerHttp(int sockfd)
    {
        char buffer[10240];
        ssize_t n = recv(sockfd ,buffer, sizeof(buffer) - 1, 0);
        if(n > 0)
        {
            buffer[n] = 0;
            std::cout << buffer;    // 假设读取到的是完整的报文

            // 返回响应
            // std::string text = "hello world";
            // std::string text = "<html>\r\n<boby>\r\n<h3>hello world<h3>\r\n</boby>\r\n</html>";
            
            HttpRequest req;
            req.Deserialize(buffer);    // 反序列化
            req.Parse();                // 解析
            // req.DebugPrint();

            // std::string path = webroot + url;
            // std::string text = ReadHtmlContent(path);
            std::string text;
            bool ok = true;
            text = ReadHtmlContent(req.file_path);
            if(text.empty())
            {
                ok = false;
                std::string err_html = webroot + "/err.html";
                text = ReadHtmlContent(err_html);
            }

            std::string response_line;
            if(ok) response_line = "HTTP/1.0 200 OK\r\n";
            else response_line = "HTTP/1.0 404 Not Found\r\n";

            // response_line = "HTTP/1.0 302 Found\r\n";
            std::string response_header = "Content-Length: " + std::to_string(text.size()) + "\r\n";
            response_header += "Content-Type: " + SuffixToDesc(req.suffix) + "\r\n";
            response_header += "Set-Cookie: name=outlier&&desc=小帅\r\n"; 
            // response_header += "Location: https://blog.csdn.net/Crazy_Duck_Weng?spm=1010.2135.3001.5343\r\n";
            std::string blank_line = "\r\n";
            
            std::string response = response_line + response_header + blank_line + text;
            send(sockfd, response.c_str(), response.size(), 0);
        }
        close(sockfd);
    }

    static void* ThreadFunc(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        td->httpsvr->HandlerHttp(td->sockfd);
        delete td;
        return nullptr;
    }
private:
    Sock listensock_;
    uint16_t port_;
    std::unordered_map<std::string, std::string> contentType_;
};